import dotenv from "dotenv";
import fs from "fs";
import path from "path";
import { Page } from "puppeteer";
import puppeteer from "puppeteer-extra";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
import { sleep } from "./index";

dotenv.config();

puppeteer.use(StealthPlugin());

const password = process?.env?.OKX_PASSWORD || "";

const mnemonicList = (process?.env?.PRIVATE_KEY || "")
  .trim()
  .split(/\n/g)
  .map((value) => {
    const [name, address, ...mnemonic] = value.trim().split(/,/g);
    return { name, address, mnemonic };
  });

const BOTBROWSER_EXEC_PATH =
  "/Applications/Chromium.app/Contents/MacOS/Chromium";

const BOT_PROFILE_PATH = path.join(__dirname, "./chrome134_win10_x64.enc");

export const runPuppeteer = async ({
  name = "default",
  headless = true,
  agent,
  extensions = [],
  timezone = "Asia/Hong_Kong",
  language = "zh-CN,zh;q=0.9",
}: {
  name?: string;
  headless?: boolean;
  agent?: string;
  extensions?: string[];
  timezone?: string;
  language?: string;
}) => {
  const userDataDir = path.join(__dirname, `../../puppeteer_data/${name}`);

  // 构建启动选项
  const launchOptions = {
    headless,
    executablePath: BOTBROWSER_EXEC_PATH,
    ignoreDefaultArgs: ["--disable-extensions"],
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--enable-extensions",
      "--no-first-run",
      "--no-default-browser-check",
      `--lang=${language.split(",")[0]}`,
      `--accept-lang=${language}`,
      `--bot-profile=${userDataDir}`,
      `--fingerprint=${(Number(name.match(/(\d+)/)?.[0] || 0) + 1) * 10}`, // 指纹种子
      "--fingerprint-platform=macos", // 平台
      "--fingerprint-platform-version=10.15.8", // 平台版本
      "--fingerprint-brand=Chrome", // 品牌
      "--fingerprint-brand-version=132.0.0.0", // 品牌版本
      "--fingerprint-hardware-concurrency=8", // 硬件并发

      `--bot-profile=${BOT_PROFILE_PATH}`,

      // Fix language inconsistency
      "--navigator-language-override=zh-CN", // Set navigator language to match system
      "--navigator-languages-override=zh-CN,zh,en-US,en", // Set navigator languages

      // Fix canvas fingerprinting issue
      "--fingerprint-canvas-mode=noise", // Add noise to canvas data
      "--fingerprint-canvas-noise-level=5", // Set canvas noise level to 5%

      // Fix DNS leakage
      "--dns-prefetch-disable", // Disable DNS prefetching
      "--proxy-bypass-list=<-loopback>", // Prevent DNS leakage for local addresses
      "--disable-features=PreloadMediaEngagementData,MediaEngagementBypassAutoplayPolicies",

      "--use-gl=desktop", // 使用桌面OpenGL
      "--use-angle=gl", // 使用OpenGL作为ANGLE后端
      "--gpu-vendor-id=0x8086", // Intel的供应商ID
      "--gpu-device-id=0x3e9b", // Intel Iris的设备ID

      // 分辨率
      "--window-size=1920,1080",
    ],
    userDataDir: userDataDir,
    env: {
      TZ: timezone,
      MESA_GLSL_VERSION_OVERRIDE: "4.50",
      MESA_GL_VERSION_OVERRIDE: "4.5",
      // 分辨率
      RESOLUTION: "1920x1080",
    },
  };

  extensions.forEach((extension) => {
    if (extension === "okx") {
      const extensionPath = path.join(
        __dirname,
        "../../chrome_extension/okx/3.45.19_0"
      );
      launchOptions.args.push(`--load-extension=${extensionPath}`);
    }
  });

  // 如果提供了agent参数，添加到启动选项中
  if (agent) {
    launchOptions.args.push(`--user-agent=${agent}`);
  }

  // 启动已安装的 Chrome 浏览器并加载插件
  const browser = await puppeteer.launch(launchOptions);

  // 创建一个辅助方法来设置页面的语言
  const setPageLanguage = async (page: Page) => {
    if (page) {
      try {
        // 设置请求头
        await page.setExtraHTTPHeaders({
          "accept-language": language,
        });

        // 通过评估JavaScript来设置navigator.language和languages
        await page.evaluateOnNewDocument((lang) => {
          const primaryLang = lang.split(",")[0];
          const languages = lang.split(",").map((l) => l.split(";")[0]);

          // Override navigator.language
          Object.defineProperty(navigator, "language", {
            get: function () {
              return primaryLang;
            },
          });

          // Override navigator.languages
          Object.defineProperty(navigator, "languages", {
            get: function () {
              return languages;
            },
          });

          // Add consistent language indicators to DOM properties
          document.documentElement.lang = primaryLang;
        }, language);
      } catch (err) {
        console.error("设置页面语言失败:", err);
      }
    }
  };

  // 修改browser.newPage方法，添加语言设置
  const originalNewPage = browser.newPage.bind(browser);
  browser.newPage = async () => {
    const page = await originalNewPage();
    await setPageLanguage(page);
    return page;
  };

  return browser;
};

export const loadJquery = async (page: Page) => {
  const jqueryContent = fs.readFileSync(
    path.join(__dirname, "../lib/jquery.min.js"),
    "utf8"
  );
  await page.evaluate((jqueryContent: string) => {
    eval(jqueryContent);
  }, jqueryContent);
};

export const humanLikeDelay = async () => {
  const delay = 500 + Math.floor(Math.random() * 1500);
  await sleep(delay);
};

export const humanClick = async (page: Page, selector: string) => {
  await page.waitForSelector(selector, { visible: true });

  const element = await page.$(selector);
  const box = await element?.boundingBox();

  if (box) {
    const x = box.x + box.width / 2 + (Math.random() * 10 - 5);
    const y = box.y + box.height / 2 + (Math.random() * 10 - 5);

    if (Math.random() > 0.7) {
      await page.mouse.move(
        x + (Math.random() * 100 - 50),
        y + (Math.random() * 100 - 50)
      );
      await humanLikeDelay();
    }

    await page.mouse.move(x, y);
    await humanLikeDelay();
    await page.mouse.down();
    await sleep(Math.random() * 150 + 50);
    await page.mouse.up();
  } else {
    await page.click(selector);
  }

  await humanLikeDelay();
};

export const humanType = async (page: Page, selector: string, text: string) => {
  await page.waitForSelector(selector);
  await page.click(selector);

  for (const char of text) {
    await page.keyboard.type(char, { delay: 30 + Math.random() * 100 });

    if (Math.random() > 0.95) {
      await sleep(300 + Math.random() * 1000);
    }
  }

  await humanLikeDelay();
};
